package cn.chiship.framework.upms.biz.system.service.impl;

import cn.chiship.framework.common.constants.CommonCacheConstants;
import cn.chiship.framework.common.constants.SystemConfigConstants;
import cn.chiship.framework.common.pojo.vo.ConfigJson;
import cn.chiship.framework.common.pojo.vo.ExportDataResult;
import cn.chiship.framework.common.service.GlobalCacheService;
import cn.chiship.framework.upms.biz.system.entity.UpmsSmsCode;
import cn.chiship.framework.upms.biz.system.entity.UpmsSmsCodeExample;
import cn.chiship.framework.upms.biz.system.mapper.UpmsSmsCodeMapper;
import cn.chiship.framework.upms.biz.system.service.UpmsSmsCodeService;
import cn.chiship.sdk.cache.service.RedisService;
import cn.chiship.sdk.core.base.BaseResult;
import cn.chiship.sdk.core.base.constants.BaseConstants;
import cn.chiship.sdk.core.base.constants.RegexConstants;
import cn.chiship.sdk.core.exception.custom.BusinessException;
import cn.chiship.sdk.core.util.DateUtils;
import cn.chiship.sdk.core.util.PrintUtil;
import cn.chiship.sdk.core.util.RandomUtil;
import cn.chiship.sdk.framework.base.BaseServiceImpl;
import cn.chiship.sdk.framework.pojo.dto.export.ExportDto;
import cn.chiship.sdk.framework.pojo.dto.export.ExportTransferDataDto;
import cn.chiship.sdk.third.ali.AliDySmsUtil;
import cn.chiship.sdk.third.core.model.BaseConfigModel;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * 验证码业务接口实现层 2021/9/30
 *
 * @author lijian
 */
@Service
public class UpmsSmsCodeServiceImpl extends BaseServiceImpl<UpmsSmsCode, UpmsSmsCodeExample>
		implements UpmsSmsCodeService {

	private static final Logger LOGGER = LoggerFactory.getLogger(UpmsSmsCodeServiceImpl.class);

	@Resource
	UpmsSmsCodeMapper upmsSmsCodeMapper;

	@Resource
	GlobalCacheService globalCacheService;

	@Resource
	RedisService redisService;

	String fileName = "服务短信";

	String sheetName = "服务短信";

	String sheetTitle = "服务短信明细";

	/**
	 * 组装导出数据，此方法纯属为了同时支持同步导出与异步导出，减少代码书写
	 * @return
	 */
	public ExportDataResult assemblyExportData(Map<String, Object> paramMap) {
		List<String> labels = new ArrayList<>();
		List<List<String>> valueList = new ArrayList<>();
		labels.add("流水号");
		labels.add("设备号");
		labels.add("验证码");
		labels.add("状态");
		labels.add("类型");
		labels.add("有效期");
		UpmsSmsCodeExample upmsSmsCodeExample = new UpmsSmsCodeExample();
		List<UpmsSmsCode> upmsSmsCodes = upmsSmsCodeMapper.selectByExample(upmsSmsCodeExample);

		for (UpmsSmsCode upmsSmsCode : upmsSmsCodes) {
			List<String> values = new ArrayList<>();
			values.add(upmsSmsCode.getReferenceCode() + "");
			values.add(upmsSmsCode.getCodeDevice());
			values.add(upmsSmsCode.getCode());
			if (upmsSmsCode.getIsUsed() == BaseConstants.NO) {
				values.add("未使用");
			}
			else {
				values.add("已使用");
			}
			if (upmsSmsCode.getType() == BaseConstants.NO) {
				values.add("短信验证码");
			}
			else {
				values.add("邮箱验证码");
			}
			values.add(DateUtils.dateTime(upmsSmsCode.getGmtCreated()) + "~"
					+ DateUtils.dateTime(upmsSmsCode.getExpiryTime()));
			valueList.add(values);
		}
		int total = upmsSmsCodes.size();
		return new ExportDataResult(labels, valueList, total);
	}

	@Override
	public BaseResult get(String codeDevice, Byte deviceType) {
		switch (deviceType) {
		case 0:
			if (!codeDevice.matches(RegexConstants.MOBILE)) {
				return BaseResult.error("请输入正确的手机号码!");
			}
			break;
		case 1:
			if (!codeDevice.matches(RegexConstants.EMAIL)) {
				return BaseResult.error("请输入正确的电子邮箱!");
			}
			break;
		default:
			return BaseResult.error("不支持的设备类型!");
		}
		try {
			/*
			 * 短信厂家 smsType 是否启用 isUseSms 有效时间(分钟) expiryTime 模板编号 smsTemplate 签名内容
			 * signContent 用户密钥 smsSecretKey 用户编号 smsAccessKey
			 */
			ConfigJson configJson = globalCacheService.getSystemConfigJson(Arrays.asList(SystemConfigConstants.SMS_TYPE,
					SystemConfigConstants.IS_USE_SMS, SystemConfigConstants.EXPIRY_TIME,
					SystemConfigConstants.SMS_TEMPLATE, SystemConfigConstants.SIGN_CONTENT,
					SystemConfigConstants.SMS_ACCESS_KEY, SystemConfigConstants.SMS_SECRET_KEY));
			int expiryTime = Integer.valueOf(configJson.getString(SystemConfigConstants.EXPIRY_TIME));
			BaseResult baseResult = checkCodeDeviceIsSendCode(codeDevice);
			if (!baseResult.isSuccess()) {
				Map<String, Object> map = Maps.newHashMapWithExpectedSize(7);
				baseResult = BaseResult.ok(null);
				String code = RandomUtil.number(6);
				// 手机
				if (Byte.valueOf("0").equals(deviceType)) {
					if (String.valueOf(BaseConstants.YES)
							.equals(configJson.getString(SystemConfigConstants.IS_USE_SMS))) {
						BaseConfigModel baseConfigModel = new BaseConfigModel(
								configJson.getString(SystemConfigConstants.SMS_ACCESS_KEY),
								configJson.getString(SystemConfigConstants.SMS_SECRET_KEY));
						AliDySmsUtil aliDySmsUtil = AliDySmsUtil.getInstance().config(baseConfigModel);
						Map<String, String> paramsMap = new HashMap<>(2);
						paramsMap.put("code", code);
						aliDySmsUtil.load(configJson.getString(SystemConfigConstants.SIGN_CONTENT),
								configJson.getString(SystemConfigConstants.SMS_TEMPLATE));
						baseResult = aliDySmsUtil.sendSms(codeDevice, paramsMap);
					}
					else {
						map.put("code", code);
					}
				}
				// 邮箱
				if (Byte.valueOf("1").equals(deviceType)) {
					map.put("code", code);
				}
				map.put("msg", "验证码已发送，有效期为" + expiryTime + "分钟，注意查收");
				map.put("expiryTime", expiryTime);

				if (baseResult.isSuccess()) {
					UpmsSmsCode upmsSmsCode = new UpmsSmsCode();
					upmsSmsCode.setId(RandomUtil.uuidLowerCase());
					upmsSmsCode.setCode(code);
					upmsSmsCode.setReferenceCode(System.currentTimeMillis());
					upmsSmsCode.setExpiryTime(System.currentTimeMillis() + expiryTime * 60 * 1000);
					upmsSmsCode.setIsUsed(BaseConstants.NO);
					upmsSmsCode.setCodeDevice(codeDevice);
					upmsSmsCode.setIsDeleted(BaseConstants.NO);
					upmsSmsCode.setGmtCreated(System.currentTimeMillis());
					upmsSmsCode.setGmtModified(System.currentTimeMillis());
					upmsSmsCode.setType(deviceType);
					upmsSmsCodeMapper.insertSelective(upmsSmsCode);
					cacheSmsCode(codeDevice, code, upmsSmsCode.getExpiryTime(), expiryTime * 60);
					return BaseResult.ok(map);
				}
				else {
					return baseResult;
				}
			}
			else {
				return BaseResult.error("您已获得验证码，有效期为" + expiryTime + "分钟");
			}
		}
		catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException(e.getLocalizedMessage());
		}

	}

	@Override
	public BaseResult verification(String codeDevice, String code) {
		BaseResult baseResult = globalCacheService.verificationSmsCode(codeDevice, code);
		if (baseResult.isSuccess()) {
			setIsUsed(codeDevice, code);
		}
		return baseResult;
	}

	@Override
	public BaseResult check(String codeDevice, String code) {
		String key = String.format("%s:*:%s-%s",
				CommonCacheConstants.buildKey(CommonCacheConstants.REDIS_SMS_CODE_PREFIX), codeDevice, code);
		Set<String> keys = redisService.keys(key);
		if (keys.isEmpty()) {
			return BaseResult.error("验证码错误,请重新输入!");
		}
		key = keys.iterator().next();
		Map<String, Object> map = (Map<String, Object>) redisService.get(key);
		Long expireTime = (Long) map.get("expireTime");
		Byte isUsed = (Byte) map.get("isUsed");
		if (System.currentTimeMillis() > expireTime) {
			return BaseResult.error("验证码已失效,请重新发送!");
		}
		if (BaseConstants.YES == isUsed) {
			return BaseResult.error("验证码已使用,请重新发送!");
		}
		return BaseResult.ok();

	}

	@Override
	public BaseResult setIsUsed(String codeDevice, String code) {
		UpmsSmsCodeExample upmsSmsCodeExample = new UpmsSmsCodeExample();
		UpmsSmsCodeExample.Criteria criteria = upmsSmsCodeExample.createCriteria();
		criteria.andCodeDeviceEqualTo(codeDevice);
		criteria.andCodeEqualTo(code);
		List<UpmsSmsCode> smsCodes = upmsSmsCodeMapper.selectByExample(upmsSmsCodeExample);
		if (!smsCodes.isEmpty()) {
			UpmsSmsCode smsCode = smsCodes.get(0);
			smsCode.setIsUsed(BaseConstants.YES);
			upmsSmsCodeMapper.updateByPrimaryKey(smsCode);
		}
		return BaseResult.ok();
	}

	@Override
	public ExportTransferDataDto assemblyExportData(ExportDto exportDto) {
		List<String> labels = new ArrayList<>();
		List<List<String>> valueList = new ArrayList<>();
		labels.add("流水号");
		labels.add("设备号");
		labels.add("验证码");
		labels.add("状态");
		labels.add("类型");
		labels.add("有效期");
		UpmsSmsCodeExample upmsSmsCodeExample = new UpmsSmsCodeExample();
		List<UpmsSmsCode> upmsSmsCodes = upmsSmsCodeMapper.selectByExample(upmsSmsCodeExample);

		for (UpmsSmsCode upmsSmsCode : upmsSmsCodes) {
			List<String> values = new ArrayList<>();
			values.add(upmsSmsCode.getReferenceCode() + "");
			values.add(upmsSmsCode.getCodeDevice());
			values.add(upmsSmsCode.getCode());
			if (upmsSmsCode.getIsUsed() == BaseConstants.NO) {
				values.add("未使用");
			}
			else {
				values.add("已使用");
			}
			if (upmsSmsCode.getType() == BaseConstants.NO) {
				values.add("短信验证码");
			}
			else {
				values.add("邮箱验证码");
			}
			values.add(DateUtils.dateTime(upmsSmsCode.getGmtCreated()) + "~"
					+ DateUtils.dateTime(upmsSmsCode.getExpiryTime()));
			valueList.add(values);
		}
		int total = upmsSmsCodes.size();
		return new ExportTransferDataDto(fileName, sheetName, sheetTitle, labels, valueList, total);
	}

	private BaseResult checkCodeDeviceIsSendCode(String codeDevice) {
		String key = String.format("%s:0:%s-*",
				CommonCacheConstants.buildKey(CommonCacheConstants.REDIS_SMS_CODE_PREFIX), codeDevice);
		Set<String> keys = redisService.keys(key);
		if (keys.isEmpty()) {
			return BaseResult.error();
		}
		return BaseResult.ok();
	}

	private void cacheSmsCode(String codeDevice, String code, Long expireTime, Integer duration) {
		// 键值格式：前缀:是否使用:设备-验证码
		String key = String.format("%s:0:%s-%s",
				CommonCacheConstants.buildKey(CommonCacheConstants.REDIS_SMS_CODE_PREFIX), codeDevice, code);
		Map<String, Object> map = new HashMap<>(7);
		map.put("codeDevice", codeDevice);
		map.put("code", code);
		map.put("expireTime", expireTime);
		map.put("duration", duration);
		map.put("isUsed", BaseConstants.NO);
		redisService.set(key, map, duration);

	}

}
